package eu.scillman.net.udp;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import eu.scillman.interfaces.ICommConstants;

/**
 * A packet that can be send over UDP. (Multiple packages will function as a linked list!)
 * @author Jiri Waning
 */
/*internal*/ class DataPacket {
	
	/**
	 * The maximum amount of data bytes.
	 */
	private static final int MAX_DATA_BYTES = (ICommConstants.BUFFER_SIZE - (Long.SIZE / Byte.SIZE) - (3 * (Integer.SIZE / Byte.SIZE)));
	
	/**
	 * The byte order of the data inside the package.
	 */
	private static final ByteOrder PACKET_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN;
	
	/**
	 * The Unique IDentity of this series of packages.
	 */
	public long uId;
	
	/**
	 * The size of the complete series. (x/Y)
	 */
	public int uSize;
	
	/**
	 * The IDentity of this package within the series. (X/y)
	 */
	public int id;
	
	/**
	 * The size of the data inside this package. (Maximum of: ICommConstants.BUFFER_SIZE - 0x14)
	 */
	public int size;
	
	/**
	 * The actual data.
	 */
	public byte[] data;
	
	/**
	 * Creates a new {@code DataPacket} with the given data inside.
	 * @param data The data that the packet should hold.
	 */
	public DataPacket(byte[] data) {
		if (data.length > MAX_DATA_BYTES) {
			throw new IllegalArgumentException("The length of the data is too long. It may be max: " + MAX_DATA_BYTES);
		}
		this.data = data;
	}
	
	/** DESERIALIZE **/
	private DataPacket() {
		data = new byte[MAX_DATA_BYTES];
	}
	
	/**
	 * Serialize the {@code DataPacket} as bytes so it can be send over the connection.
	 * @return The data from the package.
	 */
	public byte[] serialize() {
		ByteBuffer buffer = ByteBuffer.allocate(ICommConstants.BUFFER_SIZE).order(PACKET_BYTE_ORDER);
		buffer.putLong(uId);
		buffer.putInt(uSize);
		buffer.putInt(id);
		buffer.putInt(size);
		buffer.put(data);
		return buffer.array();
	}
	
	/**
	 * Get the {@code DataPacket} that was send over the network as bytes.
	 * @param data The data that has been received.
	 * @return The packet based on the received data.
	 */
	public static final DataPacket deserialize(byte[] data) {
		ByteBuffer buffer = ByteBuffer.allocate(ICommConstants.BUFFER_SIZE).order(PACKET_BYTE_ORDER).put(data);
		buffer.rewind();
		
		DataPacket packet = new DataPacket();
		packet.uId = buffer.getLong();
		packet.uSize = buffer.getInt();
		packet.id = buffer.getInt();
		packet.size = buffer.getInt();
		buffer.get(packet.data, 0x00, MAX_DATA_BYTES);
		
		return packet;
	}
}
